package com.ezlcp.commons.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.fastjson2.JSONArray;
import com.ezlcp.commons.dto.Datasource;
import com.ezlcp.commons.listener.NacosDataSourceListener;
import com.ezlcp.commons.tool.Encrypt;
import com.ezlcp.commons.tool.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;

/**
 * @author Elwin ZHANG
 * @description: Druid数据源工具类<br />
 * @date 2023/6/7 13:52
 */
@Slf4j
public class DruidUtils {

    /**
     * 密码的前缀
     */
    private static final String pwPrefix = "!%*&:";
    /**
     * 密码的密钥
     */
    private static final byte[] pwSecretKey = "Lsy-160412@Elwin".getBytes(StandardCharsets.UTF_8);

    /***
     * @description 获取自定义的数据源对应的JdbcTemplate
     * @param dsId 数据源Id
     * @return com.alibaba.druid.pool.DruidDataSource
     * @author Elwin ZHANG
     * @date 2023/6/8 17:32
     */
    public static JdbcTemplate getJdbcTemplate(String dsId) {
        var ds = getDataSource(dsId);
        if (ds == null) {
            return null;
        }
        return new JdbcTemplate(ds);
    }

    /***
     * @description 获取自定义的数据源
     * @param dsId 数据源Id
     * @return com.alibaba.druid.pool.DruidDataSource
     * @author Elwin ZHANG
     * @date 2023/6/8 17:32
     */
    public static DruidDataSource getDataSource(String dsId) {
        if (StringUtils.isEmpty(dsId) || "default".equals(dsId)) {
            try {
                var object = SpringUtil.getBean("dataSource");
                return (DruidDataSource) object;
            } catch (Exception e) {
                return null;
            }
        }
        return NacosDataSourceListener.getDataSource(dsId);
    }

    /***
     * @description 创建Druid数据源
     * @param datasource 数据源实体对象
     * @return com.alibaba.druid.pool.DruidDataSource
     * @author Elwin ZHANG
     * @date 2023/6/7 10:50
     */
    public static DruidDataSource createDatasource(Datasource datasource) {
        if (datasource == null) {
            return null;
        }
        String detail = datasource.getDetail();
        if (StringUtils.isEmpty(detail) || "[]".equals(detail)) {
            return null;
        }
        DruidDataSource ds = null;
        try {
            JSONArray array = JSONArray.parseArray(detail);
            HashMap map = convertToMap(array);
            map.put(DruidDataSourceFactory.PROP_NAME, "druid-" + datasource.getIdentifier());
            ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(map);
            //ds.setBreakAfterAcquireFailure(true);
            if (ds.getMaxWait() < 500) {
                ds.setMaxWait(1000 * 3);
            }
            ds.init();
            log.info("创建DruidDataSource：" + map.get(DruidDataSourceFactory.PROP_NAME));
            return ds;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            if (ds != null) {
                try {
                    ds.close();
                } catch (Exception ee) {
                }
            }
            return null;
        }
    }

    /***
     * @description 测试数据库连接
     * @param detail 配置信息数组
     * @return String 如果测试成功，返回数据库类型;否则返回空
     * @author Elwin ZHANG
     * @date 2023/6/6 13:48
     */
    public static String testConnection(String detail) {
        if (StringUtils.isEmpty(detail) || "[]".equals(detail)) {
            return "";
        }
        DruidDataSource ds = null;
        try {
            JSONArray array = JSONArray.parseArray(detail);
            HashMap map = convertToMap(array);
            ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(map);
            //ds.setBreakAfterAcquireFailure(true);
            ds.setMaxWait(5000);
            ds.init();
            String dbType=ds.getDbType();
            var template=new JdbcTemplate(ds);
            String sql="select 1";
            var text=template.queryForObject(sql,String.class);
            log.debug("测试数据源查询值：" + text);
            ds.close();
            return dbType;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return "";
        } finally {
            if (ds != null) {
                try {
                    ds.close();
                } catch (Exception ee) {
                }
            }
        }
    }

    /***
     * @description 转换配置参数为Map格式，密码改为明文
     * @param array 配置参数数组
     * @return java.util.HashMap
     * @author Elwin ZHANG
     * @date 2023/6/6 13:50
     */
    private static HashMap convertToMap(JSONArray array) {
        HashMap map = new HashMap();
        for (int i = 0; i < array.size(); i++) {
            var object = array.getJSONObject(i);
            String key = object.getString("prop");
            String value = object.getString("value");
            if ("password".equals(key)) {
                value = DruidUtils.getSourcePassword(value);
            }
            map.put(key, value);
        }
        return map;
    }


    /***
     * @description 获取加密后的密码
     * @param password 原密码
     * @return java.lang.String 加密后的密码
     * @author Elwin ZHANG
     * @date 2023/6/6 11:48
     */
    public static String getEncryptPassword(String password) {
        if (StringUtils.isEmpty(password)) {
            return "";
        }
        if (password.startsWith(pwPrefix)) {
            return password;
        }
        String newText = Encrypt.aesEncode(password, pwSecretKey);
        return pwPrefix + newText;
    }

    /***
     * @description 获取原始密码
     * @param encPassword 加密后的密码
     * @return java.lang.String  原始密码
     * @author Elwin ZHANG
     * @date 2023/6/6 11:51
     */
    public static String getSourcePassword(String encPassword) {
        if (StringUtils.isEmpty(encPassword)) {
            return "";
        }
        if (!encPassword.startsWith(pwPrefix)) {
            return encPassword;
        }
        String text = encPassword.substring(pwPrefix.length());
        return Encrypt.aesDecode(text, pwSecretKey);
    }

}
